//
//  parser.h
//  iphttpd
//
//  Created by Zhibiao Pan on 11-11-12.
//  Copyright 2011年 PanZhibiao. All rights reserved.
//

#ifndef iphttpd_parser_h
#define iphttpd_parser_h

#include <stdio.h>

#define IPHTTPD_SEEK_CUR 1
#define IPHTTPD_SEEK_SET 2

namespace iphttpd {
  
  struct IPEntry {
    unsigned int begin_ip;
    unsigned int   end_ip;
    const char   *country;
    const char      *area;
  };
  
  bool Ip2Str(char *buf, unsigned int buf_len, unsigned int ip);
  
  // 纯真IP库解析器
  class CZParser {
  public:
    CZParser();
    ~CZParser();
    
    int Init(const char *file);
    bool GetLocation(const char *ip_str, unsigned int len, IPEntry &ip_entry);
    unsigned int GetDBSize() { return db_size_; }
    
    static unsigned int IP2Long(const char* szIPStr, unsigned int nIPLen);
    
  private:
    int                   fd_;
    unsigned int     db_size_;
    unsigned int    first_ip_;
    unsigned int     last_ip_;
    unsigned int total_count_;
    
    unsigned char *data_begin_prt_;
    
    unsigned int Read3Byte(unsigned char **p);
    unsigned int Read4Byte(unsigned char **p);
    inline void Seek(unsigned char **p,
                     unsigned int nOffset, int nSeekType = IPHTTPD_SEEK_SET);
    void GetArea(unsigned char **p, const char **buf);
    bool GetLocation(unsigned int nIPNum, IPEntry& stIPEntry);
  };
  
  /************************************************************************/
  /* 将字符串形式的IP转化成数字类型的工具类                               */
  /************************************************************************/
  class IPTokenizer
  {
  public:
    IPTokenizer(const char* szIPStr, unsigned short usIPLen)
    {
      m_szIPStr = szIPStr;
      m_ucCursor = m_szIPStr;
      m_usIPLen = usIPLen;
      if (usIPLen < 7 || usIPLen > 15)
      {
        m_bIsFailed = true;
      }
      m_bIsFailed = false;
      m_bIsEof = false;
      m_bySegNum = 0;
    }
    char NextChar()
    {
      char cRetVal = 0;
      if(m_bIsFailed) return 0;
      if (m_ucCursor < (m_szIPStr + m_usIPLen))
      {
        cRetVal = * m_ucCursor;
        m_ucCursor ++;
      } else {
        m_bIsEof = true;
      }
      return cRetVal;
    }
    unsigned char GetNextSeg()
    {
      unsigned char byRetVal = 0;
      char cNextChar;
      if(m_bIsFailed) return 0;
      if (m_bySegNum < 3)
      {
        for(int i = 0; i < 4; ++ i)
        {
          cNextChar = NextChar();
          if(m_bIsEof)
          {
            return byRetVal;
          } else if(i > 0 && cNextChar == '.')
          {
            return byRetVal;
          } else if (i == 3 && cNextChar != '.') {
            m_bIsFailed = true;
            return 0;
          } else if (cNextChar >= '0' && cNextChar <= '9') {
            byRetVal = byRetVal * 10 + (cNextChar - '0');
          } else {
            m_bIsFailed = true;
            return 0;
          }
        }
        return byRetVal;
      }
      m_bIsFailed = true;
      return 0;
    }
    unsigned int GetLongVal(){
      unsigned int  nRetVal = 0;
      if(!m_bIsFailed)
      {
        nRetVal |= GetNextSeg() << 24;
        nRetVal |= GetNextSeg() << 16;
        nRetVal |= GetNextSeg() << 8;
        nRetVal |= GetNextSeg();
        if(!m_bIsFailed)
        {
          return nRetVal;
        }
      }
      return 0;
    }
  private:
    const char  * m_szIPStr;
    const char  * m_ucCursor;
    unsigned short m_usIPLen;
    unsigned char m_bySegNum;
    bool   m_bIsFailed;
    bool   m_bIsEof;
  };

} // /namespace

#endif
